package com.opengl.textprint.views;

import android.content.Context;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

import com.opengl.textprint.utils.ClickTagHandler;
import com.opengl.textprint.utils.GameImageGetter;
import com.opengl.textprint.utils.HtmlResetUtil;
import com.opengl.textprint.utils.ThreadManager;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import kotlin.text.MatchResult;
import kotlin.text.Regex;

/**
 * 打字效果的展示view, 目前仅适用于 Html
 * Date: 2023/8/25 10:48
 */
public class ReadTypingEffectView extends AppCompatTextView {

    private static final String TEXT_ALIGN_RIGHT = "(?<=>).{0,1000}?(?=<)";

    /**
     * 用于替换展示内容的占位符
     */
    private static final String PLACE = " &ensp;";

    private final Regex regex = new Regex(TEXT_ALIGN_RIGHT);

    private String typingText;

    private String typingContent = "";

    private List<String> typingList;

    private int allTextLength;

    private int typingIndex;

    private int allTextIndex;

    private TypingRunnable runnable;

    private OnTypingState typingState;

    public ReadTypingEffectView(Context context) {
        super(context);
    }

    public ReadTypingEffectView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ReadTypingEffectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 设置需要加载的html代码段
     * @param text text
     */
    public void setTypingText(String text) {
        if (TextUtils.isEmpty(text)) return;
        typingList = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        String[] paragraph = text.split("</p>");
        if (paragraph == null || (paragraph.length == 1 && paragraph[0].contains("<img"))) {
            typingContent = paragraph[0];
            ThreadManager.getInstance().addTask(runnable == null ? (runnable = new TypingRunnable()) : runnable);
            if (typingState != null) {
                typingState.onTypingFinish();
            }
        } else {
            for (String s : paragraph) {
                typingList.add(replacedParagraph(s + "</p>", builder));
            }
            typingText = builder.toString();
            if (TextUtils.isEmpty(typingText)) {
                typingContent = text;
                ThreadManager.getInstance().addTask(runnable == null ? (runnable = new TypingRunnable()) : runnable);
                if (typingState != null) {
                    typingState.onTypingFinish();
                }
            } else {
                allTextLength = typingText.length();
                if (typingState != null) {
                    typingState.onTypingStart();
                }
                showTypingText();
            }
        }
    }

    private String replacedParagraph(String paragraph, StringBuilder textBuilder) {
        StringBuilder builder = new StringBuilder();
        int start = 0;
        Iterator<MatchResult> iterator = regex.findAll(paragraph, 0).iterator();
        while (iterator.hasNext()) {
            MatchResult result = iterator.next();
            String value = result.getValue();
            if (!TextUtils.isEmpty(value)) {
                builder.append(paragraph.substring(start, result.getRange().getStart()))
                        .append(PLACE);
                start = result.getRange().getStart() + value.length();
                if (!"&nbsp;".equals(value.trim())) {
                    value = value.replaceAll("&nbsp;", " ");
                    textBuilder.append(value).append("~");
                }
            }
        }
        String s = builder.toString();
        if (TextUtils.isEmpty(s)) {
            return paragraph;
        } else {
            builder.append(paragraph.substring(start));
            return builder.toString();
        }
    }

    private void showTypingText() {
        if (allTextIndex < allTextLength) {
            if (typingContent.contains(PLACE) || typingContent.contains("~")) {
                CharSequence nextText = typingText.subSequence(allTextIndex, allTextIndex + 1);
                if ("~".contains(nextText)) {
                    typingContent = typingContent.replaceFirst(PLACE, "");
                } else {
                    typingContent = typingContent.replaceFirst(PLACE, nextText + PLACE);
                }
                ThreadManager.getInstance().addTask(runnable == null ? (runnable = new TypingRunnable()) : runnable);
            } else {
                if (typingIndex <= typingList.size() - 1) {
                    typingContent += typingList.get(typingIndex);
                    typingIndex++;
                    showTypingText();
                }
            }
        } else {
            Log.d("ReadTypingEffectView", "打字结束");
            if (typingState != null) {
                typingState.onTypingFinish();
            }
        }
    }

    private class TypingRunnable implements Runnable {

        @Override
        public void run() {
            String tev = HtmlResetUtil.removePMargin(HtmlResetUtil.textAlignRight(HtmlResetUtil.checkFontColor(typingContent)));
            Spanned spanned = Html.fromHtml(tev, Html.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL,
                    new GameImageGetter(getContext(), 1080),
                    new ClickTagHandler(getContext(), () -> {

                    }));
            postDelayed(() -> {
                setText(spanned);
                allTextIndex++;
                showTypingText();
            }, 50);
        }
    }

    public void setTypingState(OnTypingState typingState) {
        this.typingState = typingState;
    }

    public interface OnTypingState {
        void onTypingStart();

        void onTypingFinish();
    }
}
